#include <iostream>
#include <sstream>

#include <typeinfo>


#include <cppunit/TestCase.h>
#include <cppunit/TestFixture.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestSuite.h>

#include <cppunit/ui/text/TestRunner.h>

#include "rep/rep.hpp"

using namespace std;


namespace rep{
  class SlotTest : public CppUnit::TestFixture{
  public:

    void setUp(){
      smallType = FrameType(NULL, 1, NULL, NULL);
      mediumType = FrameType(NULL, 4, NULL, NULL);
      FrameHelper::assign(&small, FrameHelper::alloc(&smallType));
      FrameHelper::assign(&medium,FrameHelper::alloc(&mediumType));
      largeType = FrameType(medium.obj, 16, NULL, NULL);
      FrameHelper::assign(&large, FrameHelper::alloc(&largeType));
    }
    void tearDown(){}
  protected:
    
    Slot small, medium, large;
    FrameType smallType, mediumType, largeType;

    void testDummy(){}

    void testSize(){
      CPPUNIT_ASSERT_EQUAL(1, FrameHelper::size(&small));
      CPPUNIT_ASSERT_EQUAL(4, FrameHelper::size(&medium));
      CPPUNIT_ASSERT_EQUAL(16, FrameHelper::size(&large));
    }

    void testHash(){
      //not much about this we can test yet.
      CPPUNIT_ASSERT(FrameHelper::hashCode(&small) == 
                     FrameHelper::hashCode(&small));
      CPPUNIT_ASSERT(FrameHelper::hashCode(&medium) == 
                     FrameHelper::hashCode(&medium));
      CPPUNIT_ASSERT(FrameHelper::hashCode(&large) == 
                     FrameHelper::hashCode(&large));
    }

    void testAssign(){
      FrameHelper::assign(FrameHelper::directLookup(&medium, 2), small.obj);
      CPPUNIT_ASSERT(FrameHelper::directLookup(&small, 0) == 
                     FrameHelper::directLookup(&medium, 2)->obj);
      CPPUNIT_ASSERT(FrameHelper::directLookup(&medium, 2)->tag == Slot::FRAME);
    }

    void testParent(){
      CPPUNIT_ASSERT(FrameHelper::parent(&large) == medium.obj);      
    }

    void testAncestry(){
      FrameHelper::assign(FrameHelper::ancestralLookup(&large, 1, 2), small.obj);
      //should put it in slot 2 of medium.
      CPPUNIT_ASSERT(FrameHelper::directLookup(&medium, 2)->tag == Slot::FRAME);
      CPPUNIT_ASSERT(FrameHelper::directLookup(&small, 0) == 
                     FrameHelper::directLookup(&medium, 2)->obj);
    }
    
  public:
    static CppUnit::Test* suite(){
      CppUnit::TestSuite *suite = new CppUnit::TestSuite("SlotTest");
      suite->addTest( new CppUnit::TestCaller<SlotTest>("testHash", 
                                                        &SlotTest::testHash));
      suite->addTest( new CppUnit::TestCaller<SlotTest>("testAssign", 
                                                        &SlotTest::testAssign));
      suite->addTest( new CppUnit::TestCaller<SlotTest>("testSize", 
                                                        &SlotTest::testSize));
      suite->addTest( new CppUnit::TestCaller<SlotTest>("testAncestry", 
                                                        &SlotTest::testAncestry));
      suite->addTest( new CppUnit::TestCaller<SlotTest>("testParent", 
                                                        &SlotTest::testParent));
      return suite;
    }
  };
};
